﻿using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace System.NETool;

public static class StringEx
{
    /// <summary>
    /// 指示指定的字符串是 null还是 Empty 字符串。
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsNullOrEmpty(this string @this) => string.IsNullOrEmpty(@this);

    /// <summary>
    /// 指示指定的字符串是 null、空还是仅由空白字符组成。
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsNullOrWhiteSpace(this string @this) => string.IsNullOrWhiteSpace(@this);

    /// <summary>
    /// 指示指定的字符串是 null还是 Empty 字符串。
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsValid(this string @this) => !string.IsNullOrEmpty(@this);

    /// <summary>
    /// 浮点数的格式化字符串（例如：0.00）
    /// </summary>
    /// <param name="decimalPlaces">小数位数</param>
    /// <returns>字符串</returns>
    public static string FormatString(int decimalPlaces)
    {
        if (decimalPlaces <= 0)
        {
            return "0";
        }

        return "0." + "0".Repeat(decimalPlaces);
    }

    /// <summary>
    /// 字符串转换为布尔值
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static bool ToBoolean(this string @this, bool def = default) => bool.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为字符
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static char ToChar(this string @this, char def = default) => char.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为十进制数
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static decimal ToDecimal(this string @this, decimal def = default) => decimal.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为双精度浮点数
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static double ToDouble(this string @this, double def = default) => double.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为单精度浮点数
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static float ToFloat(this string @this, float def = default) => float.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为字节
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static byte ToByte(this string @this, byte def = default) => byte.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为有符号字节
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static sbyte ToSByte(this string @this, sbyte def = default) => sbyte.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为短整型
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static short ToShort(this string @this, short def = default) => short.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为无符号短整型
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static ushort ToUShort(this string @this, ushort def = default) => ushort.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为整型
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static int ToInt(this string @this, int def = default) => int.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为无符号整型
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static uint ToUInt(this string @this, uint def = default) => uint.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为长整型
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static long ToLong(this string @this, long def = default) => long.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为无符号长整型
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static ulong ToULong(this string @this, ulong def = default) => ulong.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为日期时间
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static DateTime ToDateTime(this string @this, DateTime def = default) => DateTime.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 字符串转换为指定格式的日期时间
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="formatString">日期格式</param>
    /// <returns>结果</returns>
    public static DateTime ToDateTime(this string @this, string formatString) => DateTime.ParseExact(@this, formatString, CultureInfo.InvariantCulture);

    /// <summary>
    /// 字符串转换为Guid
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="def">默认值</param>
    /// <returns>结果</returns>
    public static Guid ToGuid(this string @this, Guid def = default) => Guid.TryParse(@this, out var result) ? result : def;

    /// <summary>
    /// 是否是布尔字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsBoolean(this string @this) => bool.TryParse(@this, out _);

    /// <summary>
    /// 是否是Char字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsChar(this string @this) => char.TryParse(@this, out _);

    /// <summary>
    /// 是否是Decimal字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsDecimal(this string @this) => decimal.TryParse(@this, out decimal _);

    /// <summary>
    /// 是否是Double字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsDouble(this string @this) => double.TryParse(@this, out _);

    /// <summary>
    /// 是否是Float字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsFloat(this string @this) => float.TryParse(@this, out float _);

    /// <summary>
    /// 是否是Byte字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsByte(this string @this) => byte.TryParse(@this, out _);

    /// <summary>
    /// 是否是SByte字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsSByte(this string @this) => sbyte.TryParse(@this, out _);

    /// <summary>
    /// 是否是Short字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsShort(this string @this) => short.TryParse(@this, out _);

    /// <summary>
    /// 是否是UShort字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsUShort(this string @this) => ushort.TryParse(@this, out _);

    /// <summary>
    /// 是否是Int字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsInt(this string @this) => int.TryParse(@this, out _);

    /// <summary>
    /// 是否是UInt字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsUInt(this string @this) => uint.TryParse(@this, out _);

    /// <summary>
    /// 是否是Long字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsLong(this string @this) => long.TryParse(@this, out _);

    /// <summary>
    /// 是否是ULong字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsULong(this string @this) => ulong.TryParse(@this, out _);

    /// <summary>
    /// 是否是日期字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsDateTime(this string @this) => DateTime.TryParse(@this, out _);

    /// <summary>
    /// 是否是Guid字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsGuid(this string @this) => Guid.TryParse(@this, out _);

    /// <summary>
    /// 字符串重复显示
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="count">重复次数</param>
    /// <returns>结果</returns>
    public static string Repeat(this string @this, int count)
    {
        if (count <= 0)
        {
            return string.Empty;
        }

        using var sb = new ValueStringBuilder(1024);
        sb.Append("");
        for (int i = 0; i < count; i++)
        {
            sb.Append(@this);
        }

        return sb.ToString();
    }

    /// <summary>
    /// 字符串左侧按长度截取后的字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="length">长度</param>
    /// <returns>结果</returns>
    public static string Left(this string @this, int length)
    {
        return @this.IsNullOrEmpty() ? @this : (length <= @this.Length ? @this[..length] : @this);
    }

    /// <summary>
    /// 字符串中间按长度截取后的字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="start">开始位置</param>
    /// <param name="length">长度</param>
    /// <returns>结果</returns>
    public static string Middle(this string @this, int start, int length)
    {
        return @this.IsNullOrEmpty() ? @this : (length <= @this.Length - start ? @this.Substring(start, length) : @this.Substring(start, @this.Length - start));
    }

    /// <summary>
    /// 字符串右侧按长度截取后的字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="length">长度</param>
    /// <returns>结果</returns>
    public static string Right(this string @this, int length)
    {
        return @this.IsNullOrEmpty() ? @this : length >= @this.Length ? @this : @this.Substring(@this.Length - length, length);
    }

    /// <summary>
    /// 是否数字字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsNumber(this string @this)
    {
        if (@this.IsNullOrEmpty()) return false;
        var regNumber = new Regex("^[0-9]+$");
        return regNumber.Match(@this).Success;
    }

    /// <summary>
    /// 是否数字字符串 可带正负号
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsNumberWithSign(this string @this)
    {
        if (@this.IsNullOrEmpty()) return false;
        var regNumberSign = new Regex("^[+-]?[0-9]+$");
        return regNumberSign.Match(@this).Success;
    }

    /// <summary>
    /// 是否是纯英文字母
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsPureEnglishChar(string @this)
    {
        if (@this.IsNullOrEmpty()) return false;
        var regEnglish = new Regex("^[a-zA-Z]+$");
        return regEnglish.IsMatch(@this);
    }

    /// <summary>
    /// 是否是命名空间
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsNameSpace(string @this)
    {
        if (@this.IsNullOrEmpty()) return false;
        var regEnglish = new Regex("^[a-zA-Z.]+$");
        return regEnglish.IsMatch(@this) && !@this.StartsWith('.') && !@this.EndsWith('.') && @this.SplitSeparatorCount(".") <= 3 && !@this.Contains("..") && !@this.Contains("...");
    }

    /// <summary>
    /// 字符串是否为IP地址
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static bool IsIP4(this string @this)
    {
        if (string.IsNullOrEmpty(@this)) return false;
        var strings = @this.Split(".");
        return strings.Length == 4 && strings.All(str => str.IsByte());
    }

    /// <summary>
    /// 分割字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="separator">分隔符</param>
    /// <param name="ignoreEmpty">忽略空字符串</param>
    /// <returns>结果</returns>
    public static string[] Split(this string @this, string separator, bool ignoreEmpty = false)
    {
        if (@this.IsNullOrEmpty()) return null;
        var strings = @this.Split([separator], StringSplitOptions.None);
        return !ignoreEmpty ? strings : strings.Where(str => !str.IsNullOrEmpty()).ToArray();
    }

    /// <summary>
    /// 字符串包含分隔符的个数
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="separator">分隔符</param>
    /// <returns>个数</returns>
    public static int SplitSeparatorCount(this string @this, string separator)
    {
        if (@this.IsNullOrEmpty() || !@this.Contains(separator) || separator.IsNullOrEmpty()) return 0;
        var strReplaced = @this.Replace(separator, "");
        return (@this.Length - strReplaced.Length) / separator.Length;
    }

    /// <summary>
    /// 以分隔符分割后的最后一个字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="separator">分隔符</param>
    /// <param name="ignoreEmpty">忽略空字符串</param>
    /// <returns>结果</returns>
    public static string SplitLast(this string @this, string separator, bool ignoreEmpty = false)
    {
        if (@this.SplitSeparatorCount(separator) == 0) return string.Empty;
        var strings = @this.Split(separator, ignoreEmpty);
        return strings.Length == 0 ? string.Empty : strings[^1];
    }

    /// <summary>
    /// 以分隔符分割后的第一个字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="separator">分隔符</param>
    /// <param name="ignoreEmpty">忽略空字符串</param>
    /// <returns>结果</returns>
    public static string SplitFirst(this string @this, string separator, bool ignoreEmpty = false)
    {
        if (@this.SplitSeparatorCount(separator) == 0) return string.Empty;
        var strings = @this.Split(separator, ignoreEmpty);
        return strings.Length == 0 ? string.Empty : strings[0];
    }

    /// <summary>
    /// 返回字符串分割后指定索引的字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="separator">分隔符</param>
    /// <param name="index">索引</param>
    /// <param name="ignoreEmpty">忽略空字符串</param>
    /// <returns>结果</returns>
    public static string SplitIndex(this string @this, string separator, int index, bool ignoreEmpty = false)
    {
        if (@this.SplitSeparatorCount(separator) == 0) return string.Empty;
        var strings = @this.Split(separator, ignoreEmpty);
        return strings.Length == 0 ? string.Empty : strings[index];
    }

    /// <summary>
    /// 以分隔符分割的最后一个字符串之前的字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="separator">分隔符</param>
    /// <returns>结果</returns>
    public static string SplitBeforeLast(this string @this, string separator)
    {
        if (@this.SplitSeparatorCount(separator) == 0) return string.Empty;
        int iLast = @this.LastIndexOf(separator, StringComparison.Ordinal);
        return iLast > 0 ? @this[..iLast] : @this;
    }

    /// <summary>
    /// 检测输入的邮件地址是否合法，非法则返回true。
    /// </summary>
    /// <param name="this">邮件</param>
    /// <returns>结果</returns>
    public static bool IsMail(this string @this)
    {
        if (@this.IsNullOrEmpty()) return false;
        const string strWords = "abcdefghijklmnopqrstuvwxyz_-.0123456789"; //定义合法字符范围

        string strTmp = @this.Trim();
        //检测输入字符串是否为空，不为空时才执行代码。
        if (strTmp.IsNullOrEmpty()) return false;

        //判断邮件地址中是否存在一个“@”号
        if (@this.SplitSeparatorCount("@") != 1) return false;

        //以“@”号为分割符，把地址切分成两部分，分别进行验证。
        var strChars = strTmp.Split('@');
        if (strChars.Length != 2) return false;
        if (strChars[0].IsNullOrEmpty() || strChars[1].IsNullOrEmpty()) return false;
        strTmp = @this.Replace("@", "").ToLower();

        //逐个字进行验证，如果超出所定义的字符范围strWords，则表示地址非法。
        return !strTmp.Where((_, i) => SplitSeparatorCount(strWords, strTmp.Substring(i, 1)) == 0).Any();
    }

    /// <summary>
    /// 英文字符串转换为ASCII编码的数组
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>结果</returns>
    public static byte[] ToEnByteArray(this string @this) => @this.IsNullOrEmpty() ? Array.Empty<byte>() : Encoding.ASCII.GetBytes(@this);

    /// <summary>
    /// ASCII编码的数组转换为英文字符串
    /// </summary>
    /// <param name="this">数组</param>
    /// <returns>结果</returns>
    public static string ToEnString(this byte[] @this) => @this.IsNullOrEmpty() ? "" : Encoding.ASCII.GetString(@this).Trim('\0').Trim();

    /// <summary>
    /// 获取两个字符串之间的子字符串
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="x">左边界字符串</param>
    /// <param name="y">右边界字符串</param>
    /// <returns>结果</returns>
    /// <remarks>与 GetBefore 不同，此方法会修剪结果</remarks>
    public static string Between(this string @this, string x, string y)
    {
        if (@this.IsNullOrEmpty()) return @this;
        if (x.IsNullOrEmpty()) throw new ArgumentException("Params must not empty.", nameof(x));
        if (y.IsNullOrEmpty()) throw new ArgumentException("Params must not empty.", nameof(y));

        var xPos = @this.IndexOf(x, StringComparison.Ordinal);
        var yPos = @this.LastIndexOf(y, StringComparison.Ordinal);

        if (xPos == -1 || yPos == -1) return string.Empty;
        var startIndex = xPos + x.Length;
        return startIndex >= yPos ? string.Empty : @this.Substring(startIndex, yPos - startIndex).Trim();
    }

    /// <summary>
    /// 返回去掉最左边指定数量字符后的字符串
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="count">要去掉的字符数量</param>
    /// <returns>结果</returns>
    public static string RemoveLeft(this string @this, int count)
    {
        if (@this.IsNullOrEmpty()) return @this;
        return @this.Length <= count ? "" : @this[count..];
    }

    /// <summary>
    /// 返回去掉最右边指定数量字符后的字符串
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="count">要去掉的字符数量</param>
    /// <returns>结果</returns>
    public static string RemoveRight(this string @this, int count)
    {
        if (@this.IsNullOrEmpty()) return @this;
        return @this.Length <= count ? "" : @this[..^count];
    }

    /// <summary>
    /// 将流量值转换为可读字符串
    /// </summary>
    /// <param name="flow">流量值</param>
    /// <param name="format">格式化字符串</param>
    /// <returns>结果</returns>
    public static string ToShowString(ulong flow, string format = "F1")
    {
        if (flow < Math.Pow(2, 10)) return $"{flow} byte";
        double df = flow * 1.0 / Math.Pow(2, 10);
        if (df < Math.Pow(2, 10)) return $"{df.ToString(format)} KB";
        df /= (ulong)Math.Pow(2, 10);
        if (df < Math.Pow(2, 10)) return $"{df.ToString(format)} MB";
        df /= (ulong)Math.Pow(2, 10);
        if (df < Math.Pow(2, 10)) return $"{df.ToString(format)} GB";
        df /= (ulong)Math.Pow(2, 10);
        if (df < Math.Pow(2, 10)) return $"{df.ToString(format)} TB";
        df /= (ulong)Math.Pow(2, 10);
        if (df < Math.Pow(2, 10)) return $"{df.ToString(format)} PB";
        df /= (ulong)Math.Pow(2, 10);
        if (df < Math.Pow(2, 10)) return $"{df.ToString(format)} EB";
        df /= (ulong)Math.Pow(2, 10);
        if (df < Math.Pow(2, 10)) return $"{df.ToString(format)} ZB";
        df /= (ulong)Math.Pow(2, 10);
        if (df < Math.Pow(2, 10)) return $"{df.ToString(format)} YB";
        return "∞";
    }

    /// <summary>
    /// 忽略大小写的字符串相等比较，判断是否与任意一个待比较字符串相等
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="strings">待比较字符串数组</param>
    /// <returns>结果</returns>
    public static bool EqualsIgnoreCase(this string @this, params string[] strings)
    {
        if (@this == null || string.IsNullOrEmpty(@this)) return false;
        return strings.Any(item => string.Equals(@this, item, StringComparison.OrdinalIgnoreCase));
    }

    /// <summary>
    /// 忽略大小写的字符串开始比较，判断是否与任意一个待比较字符串开始
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="strings">待比较字符串数组</param>
    /// <returns>结果</returns>
    public static bool StartsWithIgnoreCase(this string @this, params string[] strings)
    {
        if (@this == null || string.IsNullOrEmpty(@this)) return false;
        return strings.Any(item => item.IsValid() && @this.StartsWith(item, StringComparison.OrdinalIgnoreCase));
    }

    /// <summary>
    /// 忽略大小写的字符串结束比较，判断是否以任意一个待比较字符串结束
    /// </summary>
    /// <param name="this">字符串</param>
    /// <param name="strings">待比较字符串数组</param>
    /// <returns>结果</returns>
    public static bool EndsWithIgnoreCase(this string @this, params string[] strings)
    {
        if (@this == null || string.IsNullOrEmpty(@this)) return false;
        return strings.Any(item => item.IsValid() && @this.EndsWith(item, StringComparison.OrdinalIgnoreCase));
    }

    /// <summary>
    /// 从字符串左侧移除指定的子字符串
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="trimString">要移除的子字符串</param>
    /// <returns>结果</returns>
    public static string TrimLeft(this string @this, string trimString)
    {
        if (@this.IsNullOrEmpty() || trimString.IsNullOrEmpty()) return @this;
        while (@this.StartsWithIgnoreCase(trimString))
        {
            @this = @this[trimString.Length..];
            if (@this.IsNullOrEmpty()) break;
        }

        return @this;
    }

    /// <summary>
    /// 从字符串右侧移除指定的子字符串
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="trimString">要移除的子字符串</param>
    /// <returns>结果</returns>
    public static string TrimRight(this string @this, string trimString)
    {
        if (@this.IsNullOrEmpty() || trimString.IsNullOrEmpty()) return @this;
        while (@this.EndsWithIgnoreCase(trimString))
        {
            @this = @this[..^trimString.Length];
            if (@this.IsNullOrEmpty()) break;
        }

        return @this;
    }

    /// <summary>
    /// 计算字符串的MD5哈希值并返回十六进制字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>MD5哈希值的十六进制字符串</returns>
    public static string MD5(this string @this) => Encoding.UTF8.GetBytes(@this ?? "").MD5();

    /// <summary>
    /// 计算字符串的SHA1哈希值并返回十六进制字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>SHA1哈希值的十六进制字符串</returns>
    public static string SHA1(this string @this) => Encoding.UTF8.GetBytes(@this ?? "").SHA1();

    /// <summary>
    /// 计算字符串的SHA256哈希值并返回十六进制字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>SHA256哈希值的十六进制字符串</returns>
    public static string SHA256(this string @this) => Encoding.UTF8.GetBytes(@this ?? "").SHA256();

    /// <summary>
    /// 计算字符串的SHA384哈希值并返回十六进制字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>SHA384哈希值的十六进制字符串</returns>
    public static string SHA384(this string @this) => Encoding.UTF8.GetBytes(@this ?? "").SHA384();

    /// <summary>
    /// 计算字符串的SHA512哈希值并返回十六进制字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>SHA512哈希值的十六进制字符串</returns>
    public static string SHA512(this string @this) => Encoding.UTF8.GetBytes(@this ?? "").SHA512();

    /// <summary>
    /// 计算字符串的SHA3_256哈希值并返回十六进制字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>SHA3_256哈希值的十六进制字符串</returns>
    public static string SHA3_256(this string @this) => Encoding.UTF8.GetBytes(@this ?? "").SHA3_256();

    /// <summary>
    /// 计算字符串的SHA3_384哈希值并返回十六进制字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>SHA3_384哈希值的十六进制字符串</returns>
    public static string SHA3_384(this string @this) => Encoding.UTF8.GetBytes(@this ?? "").SHA3_384();

    /// <summary>
    /// 计算字符串的SHA3_512哈希值并返回十六进制字符串
    /// </summary>
    /// <param name="this">字符串</param>
    /// <returns>SHA3_512哈希值的十六进制字符串</returns>
    public static string SHA3_512(this string @this) => Encoding.UTF8.GetBytes(@this ?? "").SHA3_512();

    /// <summary>
    /// 生成PBKDF2哈希字符串
    /// </summary>
    /// <param name="this">输入文本</param>
    /// <param name="iterationCount">迭代次数</param>
    /// <param name="derivedKeyLength">派生密钥长度</param>
    /// <returns>PBKDF2哈希字符串</returns>
    public static string PBKDF2(this string @this, int iterationCount = 1000, int derivedKeyLength = 32)
    {
        @this = @this ?? "";
        var salt = RandomEx.Shared.NextBytes(16);
        using var pbkdf2 = new Rfc2898DeriveBytes(@this, salt, iterationCount, HashAlgorithmName.SHA256);
        var hash = pbkdf2.GetBytes(derivedKeyLength);
        return salt.AsSpan()[..6].ToHexString() + hash.ToHexString() + salt.AsSpan()[6..].ToHexString();
    }

    /// <summary>
    /// 验证PBKDF2哈希字符串
    /// </summary>
    /// <param name="this">输入文本</param>
    /// <param name="hash">PBKDF2哈希字符串</param>
    /// <param name="iterationCount">迭代次数</param>
    /// <returns>验证结果</returns>
    public static bool PBKDF2Verify(this string @this, string hash, int iterationCount = 1000)
    {
        if (hash.Length <= 32) return false;
        if (hash.Length.Mod(2) != 0) return false;
        @this = @this ?? "";
        var salt = new byte[16];
        hash.Left(12).ToHexByteArray().CopyTo(salt.AsSpan());
        hash.Right(20).ToHexByteArray().CopyTo(salt.AsSpan()[6..]);
        var hashBytes = hash.Middle(12, hash.Length - 32).ToHexByteArray();
        var derivedKeyLength = (hash.Length - 32).Div(2);
        using var pbkdf2 = new Rfc2898DeriveBytes(@this, salt, iterationCount, HashAlgorithmName.SHA256);
        var hash2 = pbkdf2.GetBytes(derivedKeyLength);
        return hashBytes.SequenceEqual(hash2);
    }

    internal static readonly string DefaultKey = "{[<@#$%&*;':/>]}{<[(*&^%$#@!)]>}".Repeat(5);

    internal static (byte[] key, byte[] iv) GetKeyIv(this Aes aes, string key, string iv)
    {
        var aesKey = Encoding.UTF8.GetBytes(key + DefaultKey);
        var aesIv = Encoding.UTF8.GetBytes(iv + DefaultKey);
        return (aesKey[..aes.Key.Length], aesIv[..aes.IV.Length]);
    }

    internal static (byte[] key, byte[] iv) GetKeyIv(this DES des, string key, string iv)
    {
        var aesKey = Encoding.UTF8.GetBytes(key + DefaultKey);
        var aesIv = Encoding.UTF8.GetBytes(iv + DefaultKey);
        return (aesKey[..des.Key.Length], aesIv[..des.IV.Length]);
    }

    /// <summary>
    /// 使用AES算法加密字符串
    /// </summary>
    /// <param name="this">要加密的明文字符串</param>
    /// <param name="key">加密密钥</param>
    /// <param name="iv">初始化向量</param>
    /// <returns>加密后的字符串</returns>
    public static string AesEncrypt(this string @this, string key = "", string iv = "")
    {
        if (@this == null || @this.Length <= 0)
            throw new ArgumentNullException(nameof(@this));

        // 创建一个Aes对象
        using var aes = Aes.Create();
        var pair = aes.GetKeyIv(key, iv);

        // 创建一个加密器来执行流转换
        var encryptor = aes.CreateEncryptor(pair.key, pair.iv);

        // 创建用于加密的流
        using var msEncrypt = new MemoryStream();
        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
        using (var swEncrypt = new StreamWriter(csEncrypt))
        {
            // 将所有数据写入流中
            swEncrypt.Write(@this);
        }

        return msEncrypt.ToArray().ToHexString();
    }

    /// <summary>
    /// 使用AES算法解密字符串
    /// </summary>
    /// <param name="this">要解密的字符串</param>
    /// <param name="key">解密密钥</param>
    /// <param name="iv">初始化向量</param>
    /// <returns>解密后的字符串</returns>
    public static string AesDecrypt(this string @this, string key = "", string iv = "")
    {
        // 检查参数
        if (@this is not { Length: > 0 })
            throw new ArgumentNullException(nameof(@this));

        var cipherBytes = @this.ToHexByteArray();

        // 创建一个Aes对象
        using var aes = Aes.Create();
        var pair = aes.GetKeyIv(key, iv);

        // 创建一个解密器来执行流转换
        var decryptor = aes.CreateDecryptor(pair.key, pair.iv);

        // 创建用于解密的流
        using var msDecrypt = new MemoryStream(cipherBytes);
        using var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
        using var srDecrypt = new StreamReader(csDecrypt);
        // 从解密流中读取解密后的字节并将其放入字符串中
        return srDecrypt.ReadToEnd();
    }

    /// <summary>
    /// 使用DES算法加密字符串
    /// </summary>
    /// <param name="this">要加密的明文字符串</param>
    /// <param name="key">加密密钥</param>
    /// <param name="iv">初始化向量</param>
    /// <returns>加密后的字符串</returns>
    public static string DesEncrypt(this string @this, string key = "", string iv = "")
    {
        if (@this == null || @this.Length <= 0)
            throw new ArgumentNullException(nameof(@this));

        // 创建一个Des对象
        using var des = DES.Create();
        var pair = des.GetKeyIv(key, iv);

        // 创建一个加密器来执行流转换
        var encryptor = des.CreateEncryptor(pair.key, pair.iv);

        // 创建用于加密的流
        using var msEncrypt = new MemoryStream();
        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
        using (var swEncrypt = new StreamWriter(csEncrypt))
        {
            // 将所有数据写入流中
            swEncrypt.Write(@this);
        }

        return msEncrypt.ToArray().ToHexString();
    }

    /// <summary>
    /// 使用DES算法解密字符串
    /// </summary>
    /// <param name="this">要解密的字符串</param>
    /// <param name="key">解密密钥</param>
    /// <param name="iv">初始化向量</param>
    /// <returns>解密后的字符串</returns>
    public static string DesDecrypt(this string @this, string key = "", string iv = "")
    {
        // 检查参数
        if (@this is not { Length: > 0 })
            throw new ArgumentNullException(nameof(@this));

        var cipherBytes = @this.ToHexByteArray();

        // 创建一个Des对象
        using var des = DES.Create();
        var pair = des.GetKeyIv(key, iv);

        // 创建一个解密器来执行流转换
        var decryptor = des.CreateDecryptor(pair.key, pair.iv);

        // 创建用于解密的流
        using var msDecrypt = new MemoryStream(cipherBytes);
        using var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
        using var srDecrypt = new StreamReader(csDecrypt);
        // 从解密流中读取解密后的字节并将其放入字符串中
        return srDecrypt.ReadToEnd();
    }

    /// <summary>
    /// 检查字符串是否包含所有指定的子字符串。
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="values">要检查的子字符串数组</param>
    /// <returns>如果包含所有子字符串，则返回 true；否则返回 false</returns>
    public static bool ContainsAll(this string @this, params string[] values)
    {
        foreach (string value in values)
        {
            if (!@this.Contains(value, StringComparison.Ordinal))
            {
                return false;
            }
        }

        return true;
    }

    /// <summary>
    /// 检查字符串是否包含所有指定的子字符串，使用指定的字符串比较选项。
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="comparisonType">字符串比较选项</param>
    /// <param name="values">要检查的子字符串数组</param>
    /// <returns>如果包含所有子字符串，则返回 true；否则返回 false</returns>
    public static bool ContainsAll(this string @this, StringComparison comparisonType, params string[] values)
    {
        foreach (string value in values)
        {
            if (!@this.Contains(value, comparisonType))
            {
                return false;
            }
        }

        return true;
    }

    /// <summary>
    /// 检查字符串是否包含所有指定的子字符串，忽略大小写。
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="values">要检查的子字符串数组</param>
    /// <returns>如果包含所有子字符串，则返回 true；否则返回 false</returns>
    public static bool ContainsAllIgnoreCase(this string @this, params string[] values)
    {
        foreach (string value in values)
        {
            if (!@this.Contains(value, StringComparison.OrdinalIgnoreCase))
            {
                return false;
            }
        }

        return true;
    }

    /// <summary>
    /// 检查字符串是否包含任意一个指定的子字符串。
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="values">要检查的子字符串数组</param>
    /// <returns>如果包含任意一个子字符串，则返回 true；否则返回 false</returns>
    public static bool ContainsAny(this string @this, params string[] values)
    {
        foreach (string value in values)
        {
            if (@this.Contains(value, StringComparison.Ordinal))
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 检查字符串是否包含任意一个指定的子字符串，使用指定的字符串比较选项。
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="comparisonType">字符串比较选项</param>
    /// <param name="values">要检查的子字符串数组</param>
    /// <returns>如果包含任意一个子字符串，则返回 true；否则返回 false</returns>
    public static bool ContainsAny(this string @this, StringComparison comparisonType, params string[] values)
    {
        foreach (string value in values)
        {
            if (@this.Contains(value, comparisonType))
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 检查字符串是否包含任意一个指定的子字符串，忽略大小写。
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="values">要检查的子字符串数组</param>
    /// <returns>如果包含任意一个子字符串，则返回 true；否则返回 false</returns>
    public static bool ContainsAnyIgnoreCase(this string @this, params string[] values)
    {
        foreach (string value in values)
        {
            if (@this.Contains(value, StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 截断字符串到指定的最大长度，并在末尾添加省略号。
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="maxLength">最大长度</param>
    /// <returns>截断后的字符串</returns>
    public static string Truncate(this string @this, int maxLength)
    {
        const string suffix = "...";

        if (@this == null || @this.Length <= maxLength)
        {
            return @this;
        }

        int strLength = maxLength - suffix.Length;
        return @this[..strLength] + suffix;
    }

    /// <summary>
    /// 截断字符串到指定的最大长度，并在末尾添加指定的后缀。
    /// </summary>
    /// <param name="this">源字符串</param>
    /// <param name="maxLength">最大长度</param>
    /// <param name="suffix">后缀</param>
    /// <returns>截断后的字符串</returns>
    public static string Truncate(this string @this, int maxLength, string suffix)
    {
        if (@this == null || @this.Length <= maxLength)
        {
            return @this;
        }

        int strLength = maxLength - suffix.Length;
        return @this[..strLength] + suffix;
    }

    public static string Reverse(this string @this)
    {
        if (@this.Length <= 1)
        {
            return @this;
        }

        char[] chars = @this.ToCharArray();
        Array.Reverse(chars);
        return new string(chars);
    }
}
